package com.cs342.g4.memaps;

import java.util.ArrayList;
import java.util.concurrent.ExecutionException;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.ActionBar;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.WindowManager;


import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Filter;
import android.widget.Filterable;

import android.widget.Button;
import android.widget.EditText;

import android.widget.PopupWindow;
import android.widget.TextView;

import android.widget.Toast;
import asyncTasks.AutocompleteResults;

import android.widget.Toast;
import asyncTasks.DeleteFriend;
import asyncTasks.GetFriends;
import asyncTasks.GetFriendsLocations;

import asyncTasks.GetNearbyPlaces;
import asyncTasks.GetPlaceIcon;

import asyncTasks.PlaceDetailRequest;

import asyncTasks.UpdateLocation;
import asyncTasks.UploadPlace;
import basicClasses.Friend;
import basicClasses.LocInfo;
import basicClasses.LoginObject;

import basicClasses.Place;
import basicClasses.PlaceDetails;
import basicClasses.PlaceList;

import basicClasses.PlaceSearchResult;


import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnMapLongClickListener;
import com.google.android.gms.maps.GoogleMap.OnMarkerClickListener;
import com.google.android.gms.maps.LocationSource;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.MapView;
import com.google.android.gms.maps.model.BitmapDescriptor;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;

public class MainActivity extends Activity implements LocationListener, OnItemClickListener {

	SharedPreferences mPrefs;
	private GoogleMap map;
	private LocationManager locationManager;
	ArrayList<PlaceSearchResult> list;
	public static String loc = "";
	PlaceList lists;

	private final int REPEAT_EVENT = 60000;
	private Handler mRepeatEvent;
	private String curUser;
	private String pass;
	private ArrayList<LocInfo> friendLocs = new ArrayList<LocInfo>();
	@Override
	protected void onCreate(Bundle savedInstanceState) {		
		super.onCreate(savedInstanceState);
		ActionBar ab = getActionBar(); ab.setDisplayShowTitleEnabled(false); 
		this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
		setContentView(R.layout.activity_main);
		
		 AutoCompleteTextView autoCompView = (AutoCompleteTextView) findViewById(R.id.goToLoc);
		 autoCompView.setAdapter(new PlacesAutoCompleteAdapter(this, R.layout.list_item));
		 autoCompView.setOnItemClickListener(this);

		Context mContext = this.getApplicationContext();
		mPrefs = mContext.getSharedPreferences("myPrefs", MODE_PRIVATE);
		curUser = mPrefs.getString("username", "");
		pass = mPrefs.getString("password", "");

		int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getApplicationContext());
		if (resultCode == ConnectionResult.SUCCESS) {
			map = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();
			map.setMyLocationEnabled(true);

			map.setLocationSource((LocationSource) map.getMyLocation());
			locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
			//locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,400,1000, (LocationListener) this);
			Location location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);

			onLocationChanged(location);
			//map.moveCamera(CameraUpdateFactory.zoomTo(15));

		} else if (resultCode == ConnectionResult.SERVICE_MISSING ||
				resultCode == ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED ||
				resultCode == ConnectionResult.SERVICE_DISABLED) {
			Dialog dialog = GooglePlayServicesUtil.getErrorDialog(resultCode, MainActivity.this, 1);
			dialog.show();
		}	

		//handler to set location
		mRepeatEvent = new Handler();
		mRepeatEvent.postDelayed(doRepeatEvent, 0);

	}

	@Override
	public void onLocationChanged(Location location){
		LatLng latLng = new LatLng(location.getLatitude(),location.getLongitude());
		CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, 15);
		map.animateCamera(cameraUpdate);
		getNearbyLocations(location);
		locationManager.removeUpdates(this);
	}

	@Override
	public void onStatusChanged(String provider, int status, Bundle extras) { 

	}

	@Override
	public void onProviderEnabled(String provider) { 

	}

	@Override
	public void onProviderDisabled(String provider) { 

	}

	@Override	
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflater = getMenuInflater();	
		inflater.inflate(R.layout.menu_items, menu);
		return true;
	}

	@Override
	public void onResume() {
		super.onResume();
		//setUpMapIfNeeded();
		if(!loc.equals("")){
			for(int i = 0; i < lists.results.size(); i++){
				Place place = lists.results.get(i);
				if(place.name.equals(loc)){
					LatLng latLng = new LatLng(place.geometry.location.lat, place.geometry.location.lng);
					CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, 20);
					map.animateCamera(cameraUpdate);
					loc = "";
				}
			}
		}
		//handler to set location
		mRepeatEvent = new Handler();
		mRepeatEvent.postDelayed(doRepeatEvent, REPEAT_EVENT);		
	}

	//doRepeatEvent
	private Runnable doRepeatEvent = new Runnable() {
		@SuppressLint("NewApi")
		public void run(){
			Location location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
			double lat = location.getLatitude();
			double lng = location.getLongitude();
			curUser = mPrefs.getString("username", "");
			pass = mPrefs.getString("password", "");
			LocInfo locInfo = new LocInfo(lat,lng,curUser);

			//This is the async Task to send location
			if(!curUser.equals("")){
				UpdateLocation upLoc = new UpdateLocation();
				upLoc.execute(locInfo);
			}
			//async to get friends locations
			friendLocs.clear();
			GetFriendsLocations getFriendsLocs = new GetFriendsLocations();
			LoginObject lo = new LoginObject(curUser,pass);
			try {
				friendLocs = getFriendsLocs.execute(lo).get();
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (ExecutionException e) {
				e.printStackTrace();
			}
			setFriendLocs(friendLocs);

			mRepeatEvent.postDelayed(doRepeatEvent, REPEAT_EVENT);
		}

		private void setFriendLocs(ArrayList<LocInfo> friendLocs) {
			for(LocInfo friend: friendLocs){
				Marker marker = map.addMarker(new MarkerOptions()
				.position(new LatLng(friend.lat,friend.lng))
				.title(friend.username)
				.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN)));
			}
		}
	};


	public boolean onOptionsItemSelected(MenuItem item){
		switch (item.getItemId()){
		case R.id.menu_setMapType:
			View mapItemView = findViewById(R.id.menu_setMapType);
			popupMapType(mapItemView);
			return true;
		case R.id.menu_favorites:
			Intent favs = new Intent(MainActivity.this, FavoritePlacesActivity.class);
			startActivity(favs);
			return true;
		case R.id.menu_viewFriends:
			Intent vFriends = new Intent(MainActivity.this, ViewFriends.class);
			startActivity(vFriends);
			return true;
		case R.id.menu_logout:
			SharedPreferences.Editor edit = mPrefs.edit();
			edit.putString("username", "");
			edit.putString("password", "");
			edit.commit();

			Intent loginAct = new Intent(MainActivity.this, LoginActivity.class);
			startActivity(loginAct);
			finish();
			return true;
		}
		return false;
	}


	@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
	private void popupMapType(View v){
		LayoutInflater inflater = (LayoutInflater) MainActivity.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		View view = inflater.inflate(R.layout.popup_maptype, null,false);
		final PopupWindow popup = new PopupWindow(view,235,230,true);

		TextView normal = (TextView) view.findViewById(R.id.mapNormal);
		TextView hybrid = (TextView) view.findViewById(R.id.mapHybrid);
		TextView satellite = (TextView) view.findViewById(R.id.mapSatellite);
		TextView terrain = (TextView) view.findViewById(R.id.mapTerrain);

		popup.showAtLocation(v, Gravity.CENTER, 10,10);
		popup.setFocusable(true);

		normal.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				map.setMapType(GoogleMap.MAP_TYPE_NORMAL);
				popup.dismiss();
			}
		});

		hybrid.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				map.setMapType(GoogleMap.MAP_TYPE_HYBRID);
				popup.dismiss();
			}
		});

		satellite.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				map.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
				popup.dismiss();
			}
		});

		terrain.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				map.setMapType(GoogleMap.MAP_TYPE_TERRAIN);
				popup.dismiss();
			}
		});

	}

	private void setUpMapIfNeeded() {
		// Do a null check to confirm that we have not already instantiated the map.
		if (map == null) {
			map = ((MapFragment) getFragmentManager().findFragmentById(R.id.map))
					.getMap();
			// Check if we were successful in obtaining the map.
			if (map != null) {
				// The Map is verified. It is now safe to manipulate the map.

			}
		}
	}

	public boolean onPrepareOptionsMenu(Menu menu){
		MenuItem mapShow = menu.findItem(R.id.menu_backToMap);
		mapShow.setVisible(false);
		return true;		
	}

	public void getNearbyLocations(Location location) {
		String placesSearchStr = location.getLatitude()+","+location.getLongitude();
		GetNearbyPlaces getPlaces = new GetNearbyPlaces();
		lists = new PlaceList();
		GetPlaceIcon icon = new GetPlaceIcon();
		ArrayList<BitmapDescriptor> bitmap = new ArrayList<BitmapDescriptor>();
		ArrayList<Bitmap> bitmapList = new ArrayList<Bitmap>();
		ArrayList<String>  urlList = new ArrayList<String>();
		ArrayList<Marker> markers = new ArrayList<Marker>();
		try {
			lists = getPlaces.execute(placesSearchStr).get();
		} catch (InterruptedException e2) {
			e2.printStackTrace();
		} catch (ExecutionException e2) {
			e2.printStackTrace();
		}
		for(int i = 0; i < lists.results.size(); i++){
			Place place = lists.results.get(i);
			System.out.println(i + ": " + place.icon);
			urlList.add(place.icon);
			System.out.println("Icon: " + place.icon);
		}
		try {
			bitmapList = icon.execute(urlList).get();
		} catch (InterruptedException e1) {
			e1.printStackTrace();
		} catch (ExecutionException e1) {
			e1.printStackTrace();
		}
		for(Bitmap x : bitmapList) {
			bitmap.add(BitmapDescriptorFactory.fromBitmap(x));
		}
		//list = getPlaces.execute(placesSearchStr).get();
		for(int i = 0; i < lists.results.size(); i++){
			Place place = lists.results.get(i);
			Marker marker = map.addMarker(new MarkerOptions()
			.position(new LatLng(place.geometry.location.lat, place.geometry.location.lng))
			.title(place.name)
			.snippet(place.vicinity)
			.icon(bitmap.get(i)));
			markers.add(marker);
		}
		final ArrayList<Marker> marks = new ArrayList<Marker>();
		marks.addAll(markers);
		map.setOnMapLongClickListener(new OnMapLongClickListener(){

			@Override
			public void onMapLongClick(LatLng markThis) {
				for(Marker marker: marks){
					if(Math.abs(marker.getPosition().latitude - markThis.latitude) < 0.0005 && Math.abs(marker.getPosition().longitude - markThis.longitude) < 0.0005){
						Place saveThisPlace = new Place();
						curUser = mPrefs.getString("username", "");
						saveThisPlace.userName = curUser;
						saveThisPlace.name = marker.getTitle();
						saveThisPlace.id = marker.getId();
						saveMarker(saveThisPlace);
					}
				}
			}
		});
	}
	
	public void saveMarker(final Place saveThis){
		final AlertDialog.Builder ad = new AlertDialog.Builder(this);
		ad.setTitle(saveThis.name);
		ad.setMessage("Add Location to Favorites?");
		ad.setPositiveButton("Save", new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int which) {
				UploadPlace upPlace = new UploadPlace();
				upPlace.execute(saveThis);
				dialog.dismiss();
				}
				});
		ad.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int which) {
					dialog.dismiss();
				}
				});
		ad.setCancelable(true);
		ad.show();
	}
	
	
	private class PlacesAutoCompleteAdapter extends ArrayAdapter<String> implements Filterable {
	    private ArrayList<String> resultList = new ArrayList<String>();
	    PlaceSearchResult place = new PlaceSearchResult();
	    
	    public PlacesAutoCompleteAdapter(Context context, int textViewResourceId) {
	        super(context, textViewResourceId);
	    }
	    
	    @Override
	    public int getCount() {
	        return resultList.size();
	    }

	    @Override
	    public String getItem(int index) {
	        return resultList.get(index);
	    }

	    @Override
	    public Filter getFilter() {
	        Filter filter = new Filter() {
	            @Override
	            protected FilterResults performFiltering(CharSequence constraint) {
	                FilterResults filterResults = new FilterResults();
	                if (constraint != null){
	                    // Retrieve the autocomplete results.
	                	AutocompleteResults auto = new AutocompleteResults();
	                    try {
	              
							list = auto.execute(constraint.toString()).get();
							resultList.clear();
							for(int i = 0; i < list.size(); i++){
								place = list.get(i);
								resultList.add(place.description);
							}
						} catch (InterruptedException e) {
							e.printStackTrace();
						} catch (ExecutionException e) {
							e.printStackTrace();
						}
	                    
	                    
	                    // Assign the data to the FilterResults   
	                    filterResults.values = resultList;
	                    filterResults.count = resultList.size();
	                }
	                return filterResults;
	            }

	            @Override
	            protected void publishResults(CharSequence constraint, FilterResults results) {
	                if (results != null && results.count > 0) {
	                    notifyDataSetChanged();
	                }
	                else {
	                    notifyDataSetInvalidated();
	                }
	            }};
	        return filter;
	    }
	}


	@Override
	public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
		String str = (String) adapterView.getItemAtPosition(position);
		PlaceSearchResult result = list.get(position);
		PlaceDetailRequest request = new PlaceDetailRequest();
		PlaceDetails placeDetails = new PlaceDetails();
		Place place = new Place();
		try {
			placeDetails = request.execute(result.reference).get();
			if(placeDetails != null) {
				place.name = placeDetails.result.name;
				place.formatted_address = placeDetails.result.formatted_address;
				place.vicinity = placeDetails.result.vicinity;
				System.out.println(place.name);
				place.geometry = placeDetails.result.geometry;
			}
			if(place != null){
				Marker marker = map.addMarker(new MarkerOptions()
			     .position(new LatLng(place.geometry.location.lat, place.geometry.location.lng))
			     .title(place.name)
			     .snippet(place.toString()));
				LatLng latLng = new LatLng(place.geometry.location.lat,place.geometry.location.lng);
				CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, 15);
				map.animateCamera(cameraUpdate);
				
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		}
		Toast.makeText(this, result.description, Toast.LENGTH_SHORT).show();
	}
}
